#!/usr/bin/python3
# -*- coding: utf-8 -*-

from logging import getLogger
from flask import render_template, Blueprint, request, session, jsonify
from sqlalchemy import or_
from sqlalchemy.orm import joinedload

from ..core.validators import reject_if_null, reject_if_blank
from ..core.entities import Project, Job
from ..core.callbacks import CallbackLogger
from ..core.job_runner import JobRunner
from ..core.metadata import find_job as find_job_by_name
from ..core.job_runner import submit_runner
from ..models import db, ProjectPO, NodePO

bp = Blueprint('jobs', __name__)

_LOGGER = getLogger(__name__)


def find_job(
        project: Project,
        type_: str
) -> (Job, None,):
    """ 根据项目和任务类型查找任务。

    :param project: 项目。
    :param type_: 任务类型。
    :return: 符合条件的任务，如果找不到则返回 `None` 。
    :raise ValueError: 如果参数 `project` 是 `None` 。 如果参数 `type_` 是 `None` 或者只包含空白字符。
    """
    reject_if_null(project)
    reject_if_blank(type_)

    reject_if_blank(type_)
    type_ = type_.strip()

    for job_name in project.jobs:
        job = find_job_by_name(job_name)
        if not job:
            continue
        if job.type_ == type_:
            return job

    return None


@bp.route('/execution', methods=('POST',))
def execute():
    """指定的项目执行指定的任务。"""
    project_name = request.form.get('project-name', '').strip()
    job_type = request.form.get('job-type', '').strip()

    reject_if_blank(project_name)
    reject_if_blank(job_type)

    from .projects import to_project
    from .nodes import to_node

    project = to_project(
        ProjectPO.query.options(joinedload('jobs')).filter(ProjectPO.name == project_name).first()
    )
    if not project:
        raise RuntimeError('Cannot find project[name=' + project_name + ']')

    job = find_job(project, job_type)

    if not job:
        raise RuntimeError('Cannot find job[name=' + project_name + '.' + job_type + ']')

    node_names = ['test1']
    nodes = tuple(to_node(node) for node in
                  NodePO.query.options(joinedload('props')).filter(NodePO.name in node_names).all()
                  )
    runner = JobRunner(
        project=project,
        job=job,
        nodes=nodes
    )
    runner.atexit(_save_runner)
    submit_runner(runner)
    return jsonify(True)


def _save_runner(
        runner: JobRunner,
        result,
        exception: Exception,
        callback: CallbackLogger
):
    _LOGGER.debug('JobRunner finished, save to database')
    pass
